package leeon.mobile.server.bbscache;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import leeon.mobile.BBSBrowser.models.BlockObject;
import leeon.mobile.BBSBrowser.models.BoardObject;
import leeon.mobile.BBSBrowser.models.DocObject;
import leeon.mobile.server.bbscache.entity.DocMini;
import leeon.mobile.server.bbscache.entity.OffsetIndex;
import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheFactory;
import net.sf.jsr107cache.CacheManager;
import net.sf.jsr107cache.CacheStatistics;

import com.google.appengine.api.memcache.stdimpl.GCacheFactory;

/**
 * 缓存all board 和 top10
 * @author leeon
 */
public class CacheService {
	
	private static final Logger logger = Logger.getLogger(CacheService.class.getName());
	
	//存储所有版面的对象
	//存储十大贴
	private static final String ALL_KEY = "board.all";
	private static final String TOPTEN_KEY = "board.topten";
	
	@SuppressWarnings("serial")
	private static final Map<Integer, Integer> PROPS_HOUR = new HashMap<Integer, Integer>() {{
		put(GCacheFactory.EXPIRATION_DELTA, 3600);
	}};//new doc cache 的过期时间
	@SuppressWarnings("serial")
	private static final Map<Integer, Integer> PROPS_DAY= new HashMap<Integer, Integer>() {{
		put(GCacheFactory.EXPIRATION_DELTA, 12*3600);
	}};//new doc cache 的过期时间
	
	//get static 
	public static CacheStatistics getStatics() {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(Collections.emptyMap());
			
			CacheStatistics cs = cache.getCacheStatistics();
			return cs;
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "create cache error", e);
			return null;
		}
	}
	
	/**
	 * 以下是对版面信息缓存的一系列方法
	 */
	@SuppressWarnings("unchecked")
	public static List<BlockObject> getOrCreateAll(boolean alwaysCreate) {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(Collections.emptyMap());
			
			List<BlockObject> all = (List<BlockObject>)cache.get(ALL_KEY);
			if (all == null || alwaysCreate) {
				BBSBoardService service = new BBSBoardService();
				all = service.fetchBoardFromDb();
				cache.put(ALL_KEY, all);
			}
			return all;
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "create cache error", e);
		}
		return null;
	}
	
	public static void saveTotalForCacheBoard(BoardObject board) {
		List<BlockObject> all = getOrCreateAll(false);

		//找到缓存对应的版面update total
		BoardObject b = Utils.findBoard(board.getName(), null, all);
		if (b == null) return;
		
		b.setTotal(board.getTotal());
		b.setTotalG(board.getTotalG());
		board.setDocNumber(String.valueOf(board.getTotal()));
		b.setDocNumber(board.getDocNumber());
		saveAllBoard(all);
	}
		
	public static void saveAllBoard(List<BlockObject> all) {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(Collections.emptyMap());
			cache.put(ALL_KEY, all);
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "create cache error", e);
		}
	}
		
	
	/**
	 * 以下为提取十大，并将十大放入缓存的一系列方法
	 */
	@SuppressWarnings("unchecked")
	public static List<DocObject> getOrCreateTopTen(boolean alwaysCreate, boolean onlyTopTen) {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(Collections.emptyMap());
			
			List<DocObject> topTen = (List<DocObject>)cache.get(TOPTEN_KEY);
			if (topTen == null || alwaysCreate) {
				return createTopTenCache(cache, onlyTopTen);
			} else {
				return topTen;
			}
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "create cache error", e);
		}
		return null;
	}
	
	private static List<DocObject> createTopTenCache(Cache cache, boolean onlyTopTen) {
		logger.info("topten init");
		//只刷新十大
		BBSCacheService service = new BBSCacheService();
		List<DocObject> topTen = service.refreshTopTen(true);		
		cache.put(TOPTEN_KEY, topTen);
		
		return topTen;
	}
	
	/**
	 * 以下是queue new doc，存放缓存的一系列方法
	 */
	private static final String NEW_DOC_CACHE = "newdoccache.";
	public static void clearNewDocCache(BoardObject board) {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(PROPS_HOUR);
			
			String key = NEW_DOC_CACHE + board.getName();
			
			cache.remove(key);
			
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "clear cache error", e);
		}
	}
	
	public static List<String> clearNewDocAllCache(boolean realClear) {
		List<String> ret = new ArrayList<String>();
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(PROPS_HOUR);

			for (String board : BBSBoardService.BOARD_WHITE_LIST.keySet()) {
				String key = NEW_DOC_CACHE + board;
				if (cache.containsKey(key)) {
					Object o;
					if (realClear) o = cache.remove(key);
					else o = cache.get(key);
					ret.add(key.toString()+":"+o.toString());
					logger.info("cache new doc key removed:[" + key + "]");
				}
			}
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "clear cache error", e);
		}
		return ret;
	}
	
	@SuppressWarnings("unchecked")
	public static List<List<DocMini>> getNewDocCache(BoardObject board) {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(PROPS_HOUR);
			
			String key = NEW_DOC_CACHE + board.getName();
			List<List<DocMini>> ret = (List<List<DocMini>>)cache.get(key);
			return ret;
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "create cache error", e);
			return null;
		}
	}
	
	public static void setNewDocCache(BoardObject board, List<DocMini> list, List<DocMini> saving) {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(PROPS_HOUR);
			
			String key = NEW_DOC_CACHE + board.getName();
			
			List<List<DocMini>> ret = new ArrayList<List<DocMini>>();
			ret.add(list);
			ret.add(saving);
			
			cache.put(key, ret);
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "create cache error", e);
		}
	}
	
	
	/**
	 * 以下是offset index，存放缓存的一系列方法
	 */
	private static final String OFFSET_INDEX_CACHE = "offsetindex.";
	public static void clearOffsetIndexCache(BoardObject board) {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(PROPS_DAY);
			
			String key = OFFSET_INDEX_CACHE + board.getName();
			
			cache.remove(key);
			
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "clear cache error", e);
		}
	}
	
	public static List<String> clearOffsetIndexAllCache(boolean realClear) {
		List<String> ret = new ArrayList<String>();
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(PROPS_DAY);

			for (String board : BBSBoardService.BOARD_WHITE_LIST.keySet()) {
				String key = OFFSET_INDEX_CACHE + board;
				if (cache.containsKey(key)) {
					Object o;
					if (realClear) o = cache.remove(key);
					else o = cache.get(key);
					ret.add(key.toString()+":\n"+o.toString());
					logger.info("cache new doc key removed:[" + key + "]");
				}
			}
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "clear cache error", e);
		}
		return ret;
	}
	
	public static OffsetIndex getOffsetIndexCache(BoardObject board) {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(PROPS_DAY);
			
			String key = OFFSET_INDEX_CACHE + board.getName();
			OffsetIndex ret = (OffsetIndex)cache.get(key);
			return ret;
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "create cache error", e);
			return null;
		}
	}
	
	public static void setOffsetIndexCache(BoardObject board, OffsetIndex index) {
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			Cache cache = cacheFactory.createCache(PROPS_DAY);
			
			String key = OFFSET_INDEX_CACHE + board.getName();
			cache.put(key, index);
		} catch (CacheException e) {
			logger.log(Level.SEVERE, "create cache error", e);
		}
	}
	
	public static OffsetIndex getOrCreateIndex(BoardObject board, boolean alwaysCreate) {
		OffsetIndex index = getOffsetIndexCache(board);
		if (index == null || index.isEmpty() || alwaysCreate) {
			index = BBSBoardService.createOffsetIndexBoardFromDB(board);
			setOffsetIndexCache(board, index);
		}
		return index;
	}
}
